use std::any::Any;
use std::time::Duration;
use async_trait::async_trait;
use tokio::time::sleep;
use uuid::Uuid;

use protoactor_rs::actor::{Actor, ActorContext, ActorError, DefaultActorContext, Props};
use protoactor_rs::cluster::{ClusterConfig, ClusterError, ClusterSystem, InMemoryProvider, Member};

/// 示例消息 - 必须可序列化
#[derive(Debug, Clone)]
struct GetNodeInfo;

/// 示例响应 - 必须可序列化
#[derive(Debug, Clone)]
struct NodeInfoResponse {
    node_id: String,
    node_name: String,
    message: String,
}

/// 示例请求 - 必须可序列化
#[derive(Debug, Clone)]
struct GreetRequest {
    name: String,
    request_id: String,
}

/// 示例响应 - 必须可序列化
#[derive(Debug, Clone)]
struct GreetResponse {
    message: String,
    node_id: String,
    request_id: String,
}

/// 集群节点Actor
struct NodeActor {
    node_id: String,
    node_name: String,
}

#[async_trait]
impl Actor for NodeActor {
    type Context = DefaultActorContext;

    async fn receive(&self, ctx: &mut Self::Context, msg: Box<dyn Any + Send>) -> Result<(), ActorError> {
        // 处理GetNodeInfo消息
        if let Some(_) = msg.downcast_ref::<GetNodeInfo>() {
            println!("[{}] 收到节点信息请求", self.node_name);
            
            // 构建响应
            let response = NodeInfoResponse {
                node_id: self.node_id.clone(),
                node_name: self.node_name.clone(),
                message: format!("你好，我是节点 {} (ID: {})", self.node_name, self.node_id),
            };
            
            // 发送响应
            ctx.respond(response);
            
            return Ok(());
        }
        
        // 处理GreetRequest消息
        if let Some(greet) = msg.downcast_ref::<GreetRequest>() {
            println!("[{}] 收到问候请求: {}，请求ID: {}", 
                self.node_name, greet.name, greet.request_id);
            
            // 构建响应
            let response = GreetResponse {
                message: format!("你好, {}! 来自节点 {}", greet.name, self.node_name),
                node_id: self.node_id.clone(),
                request_id: greet.request_id.clone(),
            };
            
            // 发送响应
            ctx.respond(response);
            
            return Ok(());
        }
        
        println!("[{}] 收到未知消息类型", self.node_name);
        Ok(())
    }
    
    async fn started(&self, _ctx: &mut Self::Context) -> Result<(), ActorError> {
        println!("[{}] NodeActor已启动，ID: {}", self.node_name, self.node_id);
        Ok(())
    }
    
    async fn stopping(&self, _ctx: &mut Self::Context) -> Result<(), ActorError> {
        println!("[{}] NodeActor正在停止", self.node_name);
        Ok(())
    }
}

/// 运行集群节点
async fn run_node(
    node_name: &str, 
    host: &str, 
    port: u16, 
    roles: Vec<String>,
    seed_nodes: Vec<String>,
) -> Result<(), Box<dyn std::error::Error>> {
    println!("启动集群节点: {}", node_name);
    
    // 创建集群配置
    let config = ClusterConfig {
        host: host.to_string(),
        port,
        cluster_name: "protoactor-cluster-demo".to_string(),
        roles,
        heartbeat_interval: Duration::from_secs(5),
        unreachable_timeout: Duration::from_secs(15),
        auto_down_unreachable: false,
    };
    
    // 创建内存提供者（演示用，实际应使用Consul、etcd等）
    let (provider, _) = InMemoryProvider::new();
    
    // 创建集群系统
    let mut cluster = ClusterSystem::new(
        config,
        Box::new(provider),
    ).await?;
    
    // 生成唯一节点ID
    let node_id = Uuid::new_v4().to_string();
    
    // 创建并注册NodeActor
    let props = Props::from_producer(move || NodeActor {
        node_id: node_id.clone(),
        node_name: node_name.to_string(),
    });
    
    // 注册Actor类型
    cluster.register::<NodeActor>("Node", props.clone())?;
    
    // 启动集群系统
    cluster.start().await?;
    
    // 获取本地节点Actor实例
    let node_actor_pid = cluster.get_virtual_actor::<NodeActor>("Node", &node_id).await?;
    
    println!("节点 {} 已启动并加入集群", node_name);
    println!("节点虚拟Actor PID: {:?}", node_actor_pid);
    
    // 运行一段时间
    println!("节点将运行30秒后退出...");
    sleep(Duration::from_secs(30)).await;
    
    // 停止集群系统
    cluster.stop().await?;
    
    println!("节点 {} 已停止", node_name);
    Ok(())
}

/// 运行客户端
async fn run_client(host: &str, port: u16) -> Result<(), Box<dyn std::error::Error>> {
    println!("启动集群客户端");
    
    // 创建集群配置
    let config = ClusterConfig {
        host: host.to_string(),
        port,
        cluster_name: "protoactor-cluster-demo".to_string(),
        roles: vec!["client".to_string()],
        heartbeat_interval: Duration::from_secs(5),
        unreachable_timeout: Duration::from_secs(15),
        auto_down_unreachable: false,
    };
    
    // 创建内存提供者（演示用，实际应使用Consul、etcd等）
    let (provider, _) = InMemoryProvider::new();
    
    // 创建集群系统
    let mut cluster = ClusterSystem::new(
        config,
        Box::new(provider),
    ).await?;
    
    // 启动集群系统
    cluster.start().await?;
    
    println!("客户端已连接到集群");
    
    // 等待集群发现节点
    println!("等待发现集群节点...");
    sleep(Duration::from_secs(2)).await;
    
    // 获取集群成员
    let members = cluster.get_members().await;
    
    if members.is_empty() {
        println!("未发现集群节点，请确保至少有一个服务节点在运行");
    } else {
        println!("发现 {} 个集群节点:", members.len());
        
        for (i, member) in members.iter().enumerate() {
            println!("{}: {} - {} ({})", i+1, member.id, member.address, 
                member.roles.iter().cloned().collect::<Vec<String>>().join(", "));
        }
        
        // 获取节点成员
        let node_members = cluster.get_members_by_role("node").await;
        
        if !node_members.is_empty() {
            // 随机选择一个节点
            let node_member = &node_members[0];
            println!("\n将向节点 {} 发送请求", node_member.address);
            
            // 获取NodeActor引用
            // 注意：在实际场景中应该从节点获取实际的Actor ID
            let node_actor_id = format!("Node_{}", Uuid::new_v4());
            let node_pid = cluster.get_virtual_actor::<NodeActor>("Node", &node_actor_id).await?;
            
            // 发送问候请求
            for i in 1..=3 {
                let request_id = Uuid::new_v4().to_string();
                let request = GreetRequest {
                    name: format!("客户端 #{}", i),
                    request_id: request_id.clone(),
                };
                
                println!("\n发送问候请求 #{}: 请求ID={}", i, request_id);
                
                // 发送请求并等待响应
                match cluster.request::<GreetResponse>(
                    &node_pid,
                    request,
                    Duration::from_secs(5),
                ).await {
                    Ok(response) => {
                        println!("收到响应: {} (节点: {}, 请求ID: {})", 
                            response.message, response.node_id, response.request_id);
                    },
                    Err(e) => {
                        println!("请求失败: {}", e);
                    }
                }
                
                // 等待一会再发送下一个请求
                sleep(Duration::from_secs(1)).await;
            }
        } else {
            println!("未发现任何'node'角色的成员");
        }
    }
    
    // 停止集群系统
    cluster.stop().await?;
    
    println!("客户端已断开连接");
    Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("ProtoActor-RS 集群示例");
    println!("注意：此示例为概念性演示，实际功能需要完整实现集群组件");
    
    // 解析命令行参数
    let args: Vec<String> = std::env::args().collect();
    
    if args.len() < 2 {
        println!("用法:");
        println!("  节点模式: {} node <node_name> <host> <port> <roles>", args[0]);
        println!("  客户端模式: {} client <host> <port>", args[0]);
        println!("示例:");
        println!("  启动节点1: {} node node1 127.0.0.1 8080 node,master", args[0]);
        println!("  启动节点2: {} node node2 127.0.0.1 8081 node,worker", args[0]);
        println!("  启动客户端: {} client 127.0.0.1 8082", args[0]);
        return Ok(());
    }
    
    let mode = &args[1];
    
    match mode.as_str() {
        "node" => {
            if args.len() < 6 {
                println!("节点模式需要指定节点名称、主机、端口和角色");
                return Ok(());
            }
            
            let node_name = &args[2];
            let host = &args[3];
            let port = args[4].parse::<u16>()?;
            let roles = args[5].split(',').map(|s| s.to_string()).collect();
            
            // 没有种子节点，这是演示
            let seed_nodes = vec![];
            
            run_node(node_name, host, port, roles, seed_nodes).await
        },
        "client" => {
            if args.len() < 4 {
                println!("客户端模式需要指定主机和端口");
                return Ok(());
            }
            
            let host = &args[2];
            let port = args[3].parse::<u16>()?;
            
            run_client(host, port).await
        },
        _ => {
            println!("未知模式: {}，应为'node'或'client'", mode);
            Ok(())
        }
    }
} 